<?php

namespace App\Http\Controllers\QH_Api;

use App\Events\UserCourseChangeEvent;
use App\Http\Controllers\TK_Api\ApiBaseController;
use App\Http\Requests\QH\OrderStoreRequest;
use App\Http\Requests\QH\OrderSubmitRequest;
use App\ModelFilters\Qh_OrderFilter;
use App\Models\Coupon;
use App\Models\CourseColumn;
use App\Models\LearnVideo;
use App\Models\Order;
use App\Models\Qh_Cdkey;
use App\Models\Qh_Course;
use App\Models\Qh_QuestionLibrary;
use App\Models\TQ_Config;
use App\Models\User;
use App\Service\Redis\RedisBaseService;
use App\Service\Wechat\WechatPayService;
use Carbon\Carbon;
use DB;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Log;
use Symfony\Component\HttpFoundation\Response;

class OrderController extends ApiBaseController
{
    /**
     * 获取列表
     * @return JsonResponse|object
     */
    public function list() {
        $list = Order::filter(request()->all(), Qh_OrderFilter::class)
            ->selectRaw('tiku_order.id,
            tiku_order.relationId,
            tiku_order.tradeNo,
            tiku_order.wxTradeNo,
            tiku_order.price,
            tiku_order.status,
            tiku_order.status as statusText,
            tiku_order.type,
            tiku_order.type as typeText,
            tiku_order.buyAt,
            tiku_order.payAt,
            qh_courses.name as courseName,
            qh_cdkeys.code as cdkeyCode,
            qh_cdkeys.status as cdkeyStatus
            ')
            ->leftJoin('qh_courses', 'tiku_order.relationId', '=', 'qh_courses.id')
            ->leftJoin('qh_cdkeys', 'tiku_order.id', '=', 'qh_cdkeys.orderId')
            ->where('tiku_order.userId', $this->user->id)
            ->orderByDesc('tiku_order.id')
            ->paginate(request('perPage', 10));

        return $this->restful($list);
    }

    public function show($id) {
        $order = Order::selectRaw('tiku_order.id,
            tiku_order.relationId,
            tiku_order.tradeNo,
            tiku_order.wxTradeNo,
            tiku_order.price,
            tiku_order.status,
            tiku_order.status as statusText,
            tiku_order.type,
            tiku_order.type as typeText,
            tiku_order.buyAt,
            tiku_order.payAt,
            qh_courses.name as courseName,
            qh_cdkeys.code as cdkeyCode,
            qh_cdkeys.status as cdkeyStatus
            ')
            ->leftJoin('qh_courses', 'tiku_order.relationId', '=', 'qh_courses.id')
            ->leftJoin('qh_cdkeys', 'tiku_order.id', '=', 'qh_cdkeys.orderId')
            ->where('tiku_order.userId', $this->user->id)->where('tiku_order.id', $id)->firstOrFail();

        return $this->restful($order);
    }

    /**
     * 获取订单支付状态
     * @param $id
     * @param WechatPayService $payService
     * @return JsonResponse|object
     */
    public function getOrderPaymentInfo($id, WechatPayService $payService) {
        $order = Order::findOrFail($id);

        $payInfo = $payService->sign($order->wxPrepayId);
        unset($payInfo['appId']);
        $payInfo['orderId'] = $order->id;
        $payInfo['buyType'] = $order->type;
        $payInfo['tradeNo'] = $order->tradeNo;
        $payInfo['price'] = $order->price * 100;

        return $this->restful($payInfo);
    }

    /**
     * 下单
     * @param OrderSubmitRequest $request
     * @param WechatPayService $payService
     * @return JsonResponse|object
     * @throws GuzzleException
     * @throws Exception
     */
    public function submitOrder(OrderSubmitRequest $request, WechatPayService $payService) {
        $params = $request->validated();
        $course = Qh_Course::findOrFail($params['courseId']);

        $tradeNo = 'NO'.time().rand(1000, 9999);
        $price = $course->amount * 100;    // 价格，数据库记录的是元，需要x100

        // 微信下单
        $result = $payService->order([
            'body' => $params['type'] == 1 ? '购买题库' : '购买题库激活码',
            'tradeNo' => $tradeNo,
            'fee' => $price,
            'openid' => $this->user->wxOpenid
        ]);

        try {
            $order = new Order([
                'userId' => $this->user->id,
                'relationId' => $params['courseId'],
                'tradeNo' => $tradeNo,
                'price' => $course->amount,
                'type' => $params['type'],
                'buyAt' => Carbon::now(),
                'wxNonceStr' => $result['nonce_str'],
                'wxSign' => $result['sign'],
                'wxPrepayId' => $result['prepay_id']
            ]);

            $order->save();

            $payInfo = $payService->sign($result['prepay_id']);
            unset($payInfo['appId']);
            $payInfo['courseId'] = $course->id;
            $payInfo['orderId'] = $order->id;
            $payInfo['buyType'] = $order->type;
            $payInfo['tradeNo'] = $order->tradeNo;
            $payInfo['price'] = $price;

            return $this->restful($payInfo);
        }catch (Exception $e) {
            Log::error($e->getMessage(), (array)$e);
            throw new Exception('下单失败', 200);
        }
    }

    public function submitOrder2(OrderSubmitRequest $request, WechatPayService $payService) {
        $params = $request->validated();
        if ($params['type'] == 3) {
            $model = LearnVideo::find($params['courseId']);
        }elseif ($params['type'] == 4) {
            $model = CourseColumn::find($params['courseId']);
        }else {
            throw new Exception('资源已下架', 200);
        }

        $tradeNo = 'NO'.time().rand(1000, 9999);
        $price = $model->price * 100;    // 价格，数据库记录的是元，需要x100

        // 微信下单
        $result = $payService->order([
            'body' => $params['type'] == 3 ? '解锁单科' : '解锁专栏',
            'tradeNo' => $tradeNo,
            'fee' => $price,
            'openid' => $this->user->wxOpenid
        ]);

        try {
            $order = new Order([
                'userId' => $this->user->id,
                'relationId' => $params['courseId'],
                'tradeNo' => $tradeNo,
                'price' => $model->price,
                'type' => $params['type'],
                'buyAt' => Carbon::now(),
                'wxNonceStr' => $result['nonce_str'],
                'wxSign' => $result['sign'],
                'wxPrepayId' => $result['prepay_id']
            ]);

            $order->save();

            $payInfo = $payService->sign($result['prepay_id']);
            unset($payInfo['appId']);
            $payInfo['courseId'] = $model->id;
            $payInfo['orderId'] = $order->id;
            $payInfo['buyType'] = $order->type; // 3/4
            $payInfo['tradeNo'] = $order->tradeNo;
            $payInfo['price'] = $price;

            return $this->restful($payInfo);
        }catch (Exception $e) {
            Log::error($e->getMessage(), (array)$e);
            throw new Exception('下单失败', 200);
        }
    }

    /**
     * 获取下单前置信息
     * @param $id
     * @return JsonResponse|object
     */
    public function getOrderSubmitPreInfo($id) {
        $course = Qh_Course::findOrFail($id);

        // 获取支付开关
        $config = TQ_Config::where('key', 'global_config')->first();
        $paymentEnable = true;
        if ($config) {
            $configValue = json_decode($config->value);
            $paymentEnable = !is_null($configValue->payment_enable) ? $configValue->payment_enable : true;
        }

        return $this->restful([
            'id' => $course->id,
            'name' => $course->name,
            'price' => $course->amount,
            'paymentEnable' => $paymentEnable
        ]);
    }

    public function getOrderSubmitPreInfo2($id) {
        $type = request('type');
        if (empty($type)) throw new Exception('资源不存在');

        if ($type == 3) {
            $model = LearnVideo::find($id);
        }elseif ($type == 4) {
            $model = CourseColumn::find($id);
        }else {
            throw new Exception('资源不存在');
        }

        // 获取支付开关
        $config = TQ_Config::where('key', 'global_config')->first();
        $paymentEnable = true;
        if ($config) {
            $configValue = json_decode($config->value);
            $paymentEnable = !is_null($configValue->payment_enable) ? $configValue->payment_enable : true;
        }

        $expireAt = getLearnVideoExpireAt($model);
        return $this->restful([
            'id' => $id,
            'name' => $model->name,
            'price' => $model->price,
            'expireAt' => $expireAt ? ($expireAt->diffInYears(now()) > 90 ? '长期' : $expireAt->format('Y.m.d')) : now()->format('Y.m.d'),
            'paymentEnable' => $paymentEnable
        ]);
    }

    /**
     * 微信支付结果通知
     * @param WechatPayService $payService
     * @return Response
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
     */
    public function wechatNotify(WechatPayService $payService) {
        Log::debug('[微信支付通知开始]'. Carbon::now()->format('Y-m-d H:i:s'));
        $response = $payService->app->handlePaidNotify(function ($message, $fail) {
            try {
                $order = Order::where('tradeNo', $message['out_trade_no'])->first();
                if ($order) {
                    if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态，不代表支付状态
                        // 用户是否支付成功
                        if (array_get($message, 'result_code') === 'SUCCESS') {
                            if ($order->status == 1) {
                                Db::transaction(function () use ($order, $message) {
                                    $order->status = 2;
                                    $order->wxTradeNo = $message['transaction_id']; // 微信订单号
                                    $order->payAt = Carbon::now();
                                    $order->save();

                                    if($order->type == 1) {
                                        $user = User::find($order->userId);
                                        if (!$user) throw new Exception();
                                        // 将学科添加到用户
                                        $result = DB::table('qh_user_has_course')->insert([
                                            'userId' => $user->id,
                                            'sourceId' => $order->id,
                                            'courseId' => $order->relationId,
                                            'type' => 1,
                                            'created_at' => Carbon::now()
                                        ]);
                                        // 更新用户拥有的学科缓存
                                        UserCourseChangeEvent::dispatch($user->id);
                                        if (!$result) throw new Exception();
                                    }
                                    elseif ($order->type == 2) {
                                        // 创建激活码
                                        Qh_Cdkey::create([
                                            'userId' => $order->userId,
                                            'courseId' => $order->relationId,
                                            'orderId' => $order->id,
                                            'code' => generateCdkey(),
                                            'status' => 1,
                                            'created_at' => Carbon::now()
                                        ]);
                                    }
                                    // 视频课程
                                    elseif ($order->type == 3) {
                                        // 查视频
                                        $learnVideo = LearnVideo::find($order->relationId);
                                        if ($learnVideo) {
                                            $expireAt = getLearnVideoExpireAt($learnVideo);
                                            $sendRes = sendLearnVideoToUser([$learnVideo->id], $order->userId, $expireAt, 1);
                                            if (!$sendRes) $order->status = 8;  // 已支付、商品发放失败
                                        }
                                        $order->save();
                                    }
                                    // 专栏
                                    elseif ($order->type == 4) {
                                        $courseColumn = CourseColumn::find($order->relationId);
                                        if ($courseColumn) {
                                            $resource = $courseColumn->resource;
                                            if (!empty($resource)) {
                                                // 计算日期
                                                $expireAt = getCourseColumnExpireAt($courseColumn);

                                                // 题库
                                                if (!empty($resource['courses'])) {
                                                    $sendRes = sendCourseToUser($resource['courses'], $order->userId, $order->id, 1);
                                                    if (!$sendRes) $order->status = 8;  // 已支付、商品发放失败
                                                }
                                                // 文档
                                                if (!empty($resource['documents'])) {
                                                    $sendRes = sendDocumentToUser($resource['documents'], $order->userId, $order->id, 1);
                                                    if (!$sendRes) $order->status = 8;  // 已支付、商品发放失败
                                                }
                                                // 视频课程
                                                if (!empty($resource['learn_videos'])) {
                                                    $sendRes = sendLearnVideoToUser($resource['learn_videos'], $order->userId, $expireAt, 6);
                                                    if (!$sendRes) $order->status = 8;  // 已支付、商品发放失败
                                                }
                                                $order->save();
                                                DB::table('user_course_column_buy_logs')->updateOrInsert([
                                                    'userId' => $order->userId,
                                                    'dataId' => $courseColumn->id
                                                ], [
                                                    'getType' => 1,
                                                    'expireAt' => $expireAt,
                                                    'created_at' => now(),
                                                    'updated_at' => now()
                                                ]);
                                            }
                                        }
                                    }
                                });
                            }
                        }
                    } else {
                        return $fail('通信失败，请稍后再通知我');
                    }
                }
                Log::info('微信支付通知处理成功，订单ID：'.$order->id);
                return true;
            }catch (Exception $e) {
                Log::error('微信支付通知处理异常');
                Log::error(json_encode($e->getMessage()));
                Log::error(json_encode($e->getLine()));
                Log::error(json_encode($e->getFile()));
            }

            return $fail('通信失败，请稍后再通知我');
        });

        return $response->send();
    }

    /**
     * 退款成功通知
     * @param WechatPayService $payService
     * @return Response
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
     */
    public function wechatRefundNotify(WechatPayService $payService) {
        $response = $payService->app->handleRefundedNotify(function ($message, $reqInfo, $fail) {
            Log::debug('[微信退款通知]', [$message, $reqInfo]);

            if ($reqInfo['refund_status'] === 'SUCCESS') {
                $order = Order::where('tradeNo', $reqInfo['out_trade_no'])->first();
                if (!$order) {
                    Log::error('[微信退款通知] 订单没找到，退款单号：'.$reqInfo['out_refund_no']);
                    return $fail('内部错误，请稍后再试');
                }
                if ($order->status == 9) return true;

                $order->status = 9;
                // 将激活码设为无效、将题库设为无效、将使用激活码激活的题库设为无效
                // 激活码
                if ($order->type == 1) {
                    DB::table('qh_user_has_course')->where('courseId', $order->relationId)->where('userId', $order->userId)->delete();
                    // 刷新学科缓存
                    UserCourseChangeEvent::dispatch($order->userId);
                }
                elseif ($order->type == 2) {
                    $cdkey = Qh_Cdkey::where('orderId', $order->id)->first();
                    $cdkey->status = 3;
                    $cdkey->save();

                    DB::table('qh_user_has_course')->where('courseId', $cdkey->courseId)->where('userId', $cdkey->userId)->delete();
                    // 刷新学科缓存
                    UserCourseChangeEvent::dispatch($order->userId);
                }
                elseif ($order->type == 3) {
                    unlockLearnVideo($order->userId, $order->relationId);
                }
                elseif ($order->type == 4) {
                    $model = CourseColumn::find($order->relationId);
                    if ($model) unlockCourseColumnResource($order->userId, $model);
                }
                $order->save();
                return true;
            }else {
                Log::debug('[退款通知]退款失败，退款单号：'.$reqInfo['out_refund_no']);
                return $fail('内部错误，请稍后再试');
            }
        });

        return $response->send();

    }

    /**
     * 获取商品信息
     * @return JsonResponse|object
     * @throws Exception
     */
    public function getGoodsInfo()
    {
        $resourceId = request('resourceId');
        $resourceType = request('resourceType');
        if (empty($resourceId) || empty($resourceType)) throw new Exception('商品已下架');

        $acceptCouponIds = [];
        // 视频课程
        if ($resourceType == 'A') {
            $model = LearnVideo::find($resourceId);
            if (!$model || $model->is_active != 1) throw new Exception('商品已下架');

            $data = $model->toArray();
            $data['type'] = '视频课程';
            $data['metas'] = [];
            $data['form'] = [];
        }
        // 专栏
        elseif ($resourceType == 'B') {
            $model = CourseColumn::find($resourceId);
            if (!$model || $model->is_active != 1) throw new Exception('商品已下架');

            $data = $model->toArray();
            $data['type'] = '专栏';
            $data['metas'] = [];
            $data['form'] = [];
            if ($model->gift_enabled == 1) {
                $data['form'][] = [
                    'label' => '邮箱',
                    'input' => 'input',
                    'inputType' => 'email'
                ];
            }
            if (!empty($model->coupon_ids)) $model->coupon_ids;
        }
        else {
            throw new Exception('商品已下架');
        }

        // 获取优惠券
        $userCouponIds = DB::table('user_coupon')
            ->where('userId', $this->user->id)
            ->whereNull('useAt')
            ->pluck('couponId')
            ->toArray();

        $coupons = Coupon::where(function ($query) use ($userCouponIds) {
            $query->whereIn('id', $userCouponIds)
                ->orWhere('is_auto', 1);
        })
            ->when(!empty($acceptCouponIds), function (Builder $query) use ($acceptCouponIds) {
                $query->whereIn('id', $acceptCouponIds);
            })
            ->where('unlock_price', '<=', $model->price)
            ->where('is_active', 1)
            ->where('start_use_at', '<=', now())
            ->where('end_use_at', '>', now()->addSeconds(30))
            ->where('stop_get', '>', now()->addSeconds(30))
            ->get()->toArray();
        $data['coupons'] = $coupons;

        return $this->restful($data);
    }

    /**
     * 提交订单
     * @param OrderStoreRequest $request
     * @param WechatPayService $payService
     * @return JsonResponse|object
     * @throws GuzzleException
     * @throws \Throwable
     */
    public function store(OrderStoreRequest $request, WechatPayService $payService)
    {
        $params = $request->validated();

        $body = null;       // 产品名，微信下单用
        $tradeNo = 'NO'.time().rand(1000, 9999);

        // 视频课程
        if ($params['resourceType'] == 'A') {
            $model = LearnVideo::find($params['resourceId']);
            if (!$model || $model->is_active != 1) throw new Exception('商品已下架');
            $body = '单科开通';
            $orderType = 3;
        }
        // 专栏
        elseif ($params['resourceType'] == 'B') {
            $model = CourseColumn::find($params['resourceId']);
            if (!$model || $model->is_active != 1) throw new Exception('商品已下架');
            $body = '专栏开通';
            $orderType = 4;
        }else {
            throw new Exception('商品不存在');
        }

        $totalPrice = $model->price;    // 实际支付金额

        // 验证优惠券
        $useCoupon = null;
        $couponLog = null;
        if (!empty($params['couponId'])) {
            $coupon = Coupon::find($params['couponId']);
            if (!$coupon || $coupon->is_active != 1) throw new Exception('优惠券无效');
            if (Carbon::make($coupon->end_use_at)->lt(now())) throw new Exception('优惠券已过期');
            if (Carbon::make($coupon->start_use_at)->gt(now())) throw new Exception('优惠券不可用');
            if ($coupon->is_auto != 1) {
                // 判断是否领取了优惠券
                $couponLog = DB::table('user_coupon')
                    ->where('userId', $this->user->id)
                    ->where('couponId', $params['couponId'])->first();
                if (!$couponLog || $coupon->$couponLog != null) throw new Exception('优惠券无效');

            }
            // 自动领取优惠券
            else {
                DB::table('user_coupon')->insert([
                    'userId' => $this->user->id,
                    'couponId' => $params['couponId'],
                    'getAt' => now(),
                    'created_at' => now()
                ]);

            }
            $totalPrice = ($totalPrice - $coupon->free_price) > 0 ? $totalPrice - $coupon->free_price : 0;
            $useCoupon = $coupon;
        }

        DB::beginTransaction();
        try {
            // 入库订单
            $order = Order::create([
                'userId' => $this->user->id,
                'relationId' => $model->id,
                'tradeNo' => $tradeNo,
                'price' => $totalPrice,
                'status' => 1,
                'type' => $orderType,
                'buyAt' => now()
            ]);

            // 优惠券处理
            if ($useCoupon) {
                if ($couponLog && $couponLog->useAt == null) {
                    // 更新
                    DB::table('user_coupon')
                        ->where('id', $couponLog->id)
                        ->update([
                            'useAt' => now(),
                            'orderId' => $order->id,
                            'updated_at' => now()
                        ]);
                }else {
                    // 创建
                    DB::table('user_coupon')->insert([
                        'userId' => $this->user->id,
                        'couponId' => $useCoupon->id,
                        'getAt' => now(),
                        'useAt' => now(),
                        'orderId' => $order->id,
                        'created_at' => now(),
                        'updated_at' => now()
                    ]);
                }
            }

            if ($totalPrice > 0) {
                // 微信下单
                $wxRes = $payService->order([
                    'tradeNo' => $tradeNo,
                    'body' => $body,
                    'openid' => $this->user->wxOpenid,
                    'fee' => $totalPrice * 100,   // 换算成：分
                ]);

                $order->wxNonceStr = $wxRes['nonce_str'];
                $order->wxSign = $wxRes['sign'];
                $order->wxPrepayId = $wxRes['prepay_id'];
                $order->save();

                $payInfo = $payService->sign($wxRes['prepay_id']);
                unset($payInfo['appId']);
                $payInfo['orderId'] = $order->id;
                $payInfo['tradeNo'] = $order->tradeNo;
                $payInfo['buyType'] = $orderType;
                $payInfo['price'] = $totalPrice;
                $payInfo['needPay'] = true;
            }else {
                $payInfo = [
                    'needPay' => false
                ];
            }
            DB::commit();
            return $this->restful($payInfo);
        }catch (Exception $e) {
            DB::rollBack();
            Log::error('ORDER-SUBMIT', array($e));
            return $this->restful(null, false, '下单失败');
        }
    }
}
